/*
 * Project: Daycare Web Application
 * Package: com.madetoordersoftware.daycare.business
 * File:    ChildMgr
 * Created: Jun 3, 2010
 */
/**
 * Copyright (c) 2010 Made 2 Order Software, LLC
 *
 * All rights reserved. No part of this software may be reproduced, stored in a retrieval system, or
 * transmitted in any form or by any means, without the prior written permission of Made 2 Order Software.
 *
 * You may not distribute the URL or redistribute the files to third parties. You may transfer the files onto
 * a single storage device so long as you can prove ownership of the software. You may not reverse engineer,
 * decompile, or disassemble the software or media files. You may not modify or translate the software or
 * media, or distribute copies of the software or media without the written consent of Made 2 Order Software,
 * LLC.
 */
package com.made2ordersoftware.daycare.business;

import com.made2ordersoftware.daycare.domain.ChildEntity;
import com.made2ordersoftware.daycare.domain.ChildProfileEntity;
import com.made2ordersoftware.daycare.domain.ParentEntity;
import com.made2ordersoftware.daycare.domain.TimeWatchedEntity;
import com.made2ordersoftware.daycare.domain.enums.Gender;
import com.made2ordersoftware.daycare.domain.enums.WatchCode;
import com.made2ordersoftware.daycare.service.ChildDao;
import com.made2ordersoftware.daycare.service.FeesDao;
import com.made2ordersoftware.daycare.service.ParentDao;
import com.made2ordersoftware.daycare.service.TimeWatchedDao;
import com.made2ordersoftware.exceptions.BusinessException;
import com.made2ordersoftware.exceptions.DAOException;
import com.made2ordersoftware.service.exceptions.NonexistentEntityException;
import com.made2ordersoftware.util.DateUtility;
import java.sql.Timestamp;
import java.util.Date;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityExistsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Class used to manage all actions performed with a Child object.
 *
 * @author David Canning <dcannin@gmail.com>
 * @version 1.0.0
 */
@Stateless
public class ChildMgr {

    private static final Logger LOG = LoggerFactory.getLogger(ChildMgr.class);
    @EJB
    private ChildDao c_dao;
    @EJB
    private ParentDao p_dao;
    @EJB
    private TimeWatchedDao t_dao;
    @EJB
    private FeesDao f_dao;

    /**
     * Adds an instance of <code>Child</code> to the datasource.
     *
     * @param parentId  The unique identifier of the Parent.
     * @param firstName Th first name of the Child.
     * @param lastName  The last name of the Child.
     * @param nickname  The nickname of the Child.
     * @param birthDate The birth date of the Child.
     * @param comments  Any comments needed by the day care for the Child.
     * @param gender    The gender of the child.
     *
     * @return An instance of the newly created ChildEntity
     *
     * @throws DAOException               Thrown for all exceptions in DAO layer.
     * @throws NonexistentEntityException Parent does not exist in system.
     */
    public ChildEntity addChild(long parentId, String firstName, String lastName, String nickname,
            Date birthDate, String comments, Gender gender)
            throws EntityExistsException, DAOException, NonexistentEntityException {
        LOG.info("Start add child with name {} {}.", firstName, lastName);

        ChildEntity child = new ChildEntity(firstName, lastName);
        ChildProfileEntity info = new ChildProfileEntity(birthDate, gender);

        // Set non-required fields if they are not null.
        if (nickname != null) {
            info.setNickname(nickname);
        }

        if (comments != null) {
            info.setComments(comments);
        }

        child.setChildProfile(info);
        info.setChild(child);

        ParentEntity parent = p_dao.findEntity(parentId);

        if (parent == null) {
            throw new NonexistentEntityException();
        }

        c_dao.create(child);
        parent.addChild(child);
        p_dao.update(parent);
        LOG.info("Child added successfully");

        return child;
    }

    /**
     * Sign child into the day care system.
     *
     * @param parentId   Unique ID for parent entity.
     * @param childId    Unique ID for child entity.
     * @param dateTimeIn Date and time child is being signed into system.
     * @param watchCode  Category in which the child is being signed in as, see @link WatchCode.
     *
     * @throws DAOException      Any exception thrown by the DAO layer, usually a database exception.
     * @throws BusinessException Thrown is child is already signed into system. This is determined by a record
     *                           with a sign in timestamp but without a signout timestamp.
     */
    public void signInChild(long parentId, long childId, Timestamp dateTimeIn, WatchCode watchCode)
            throws DAOException, BusinessException {
        LOG.info("Inside signInChild.");
        LOG.info("Verify child with id {} is not already signed in.", childId);

        if (t_dao.findSignInRecord(childId) != null) {
            throw new BusinessException("Child is already signed into system.");
        }

        ChildEntity child = c_dao.findEntity(childId);
        ParentEntity parent = p_dao.findEntity(parentId);

        if (child == null) {
            throw new BusinessException("Child ID does not exist in system.");
        }

        if (parent == null) {
            throw new BusinessException("Parent ID does not exist in system.");
        }

        LOG.info("Start sign in of child with id {}.", childId);

        int age = DateUtility.calculateAge(child.getChildProfile().getBirthDate());
        TimeWatchedEntity time = new TimeWatchedEntity(parent, child, dateTimeIn,
                f_dao.getFeeByAgeAndWatchCode(age, watchCode), age);

        t_dao.create(time);
        LOG.info("Finished sign in of child at {}.", dateTimeIn);
    }

    /**
     * Sign child out of day care system.
     *
     * @param childId     Unique ID for child entity.
     * @param dateTimeOut Date and time child is being signed into system.
     *
     * @throws DAOException      Any exception thrown by the DAO layer, usually a database exception.
     * @throws BusinessException Thrown is child is not signed into system yet. This is determined by no
     *                           record with a sign in timestamp and without a signout timestamp.
     */
    public void signOutChild(long childId, Timestamp dateTimeOut) throws DAOException, BusinessException {

        LOG.info("Make sure child with id {} is signed in.", childId);
        TimeWatchedEntity time = t_dao.findSignInRecord(childId);

        if (time == null) {
            throw new BusinessException("Child is not signed into system yet.");
        }

        // Validate date and time are correct.
        if (time.getDateTimeIn().after(dateTimeOut)) {
            throw new BusinessException("Sign out Time cannot be before sign in time.");
        }

        if (time.getDateTimeIn().equals(dateTimeOut)) {
            throw new BusinessException("Sign in time and sign out time cannot be the same.");
        }

        time.setDateTimeOut(dateTimeOut);
        t_dao.update(time);
        LOG.info("Child with id {} signed out successfully.", childId);
    }
}
